package com.sise.dubbo.redislock.controller;

import com.sise.dubbo.redislock.dto.GoodsDTO;
import com.sise.dubbo.redislock.service.GoodsService;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.JedisCommands;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author idea
 * @data 2019/1/17
 */
@RestController
@RequestMapping(value = "/redisLock")
public class RedisLockController {

    @Autowired
    private Redisson redisson;

    @Autowired
    private GoodsService goodsService;

    @Resource
    private RedisTemplate<String, GoodsDTO> redisTemplate;


    /**
     * 自定义 通过incr来实现抢购的demo，缺点在于锁不能自旋处理，有效期较短
     *
     * @param id
     * @return
     */
    @GetMapping(value = "/getStore")
    public boolean getStore(int id) {
        //使用redis自增的分布式lock
        String lockName = "lock";
        long incrkey = redisTemplate.opsForValue().increment(lockName, 1);
        redisTemplate.expire(lockName, 10, TimeUnit.SECONDS);
        try {
            System.out.println(incrkey);
            //只认拿到了1的那个用户拿锁成功，其他请求均被拒绝。
            //至少能够防止超卖情况出现，但是可能会出现第一个请求抢锁成功，后边请求全部直接释放，（乐观锁）
            if (incrkey == 1) {
                //扣库存的核心代码
                goodsService.exchangeGoods(id);
            }
        } catch (Exception e) {
            System.out.println("扣库存服务，抛出了异常！");
        } finally {
            redisTemplate.opsForValue().increment("lock", -1);
        }
        return true;
    }




    /**
     * redis里面的setnx操作(定时锁的时间，以秒为单位)
     */
    private Long setNx(String key, String value, Integer time) {
        RedisCallback<Long> callback = (connection) -> {
            JedisCommands jedisCommands = (JedisCommands) connection.getNativeConnection();
            return jedisCommands.setnx(key, value);
        };
        Long result = redisTemplate.execute(callback);
        redisTemplate.expire(key, time, TimeUnit.SECONDS);
        return result;
    }






    /**
     * 通过redisson的分布式锁来实现加锁
     *
     * @param id
     * @return
     */
    @GetMapping(value = "/getStore2")
    public boolean getStore2(int id) {
        String lockName = "lock";
        RLock rLock = redisson.getLock(lockName);
        rLock.lock();
        try {
            goodsService.exchangeGoods(id);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rLock.unlock();
        }
        return true;
    }


    @Bean
    public Redisson redisson() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379").setDatabase(0);
        return (Redisson) Redisson.create(config);
    }

}
